package com.yifei.service.auth.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.GifCaptcha;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.yifei.constants.RedisKeyConstants;
import com.yifei.constants.SystemConstants;
import com.yifei.model.dto.auth.CaptchaResult;
import com.yifei.model.dto.auth.LoginResult;
import com.yifei.model.dto.auth.UserAuthInfo;
import com.yifei.model.entity.auth.SysUserDetails;
import com.yifei.model.enums.ResultCode;
import com.yifei.service.auth.AuthService;
import com.yifei.service.system.SysUserService;
import com.yifei.utils.JwtUtil;
import com.yifei.utils.RedisUtil;
import com.yifei.utils.SecurityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * @Description: 权限接口
 * @Author: yiFei
 * @date: 2023/9/22 19:45
 */
@Service("authService")
public class AuthServiceImpl implements AuthService {

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private SysUserService sysUserService;


    /**
     * 登录
     *
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @Override
    public LoginResult login(String username, String password) {
        // 将用户名和密码封装成 UsernamePasswordAuthenticationToken 传入 authenticate 进行校验
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(username.toLowerCase().trim(), password);
        // authenticationManager.authenticate 会调用 loadUserByUserName
        // 会返回一个 实现了 UserDetail 的对象 放在 authentication.principal 中
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        return jwtUtil.createJwtToken(authentication);
    }

    /**
     * 退出登录
     */
    @Override
    public void logout() {
        // 本系统清除对应权限表示删除，用户可以凭借原始 token 对公共资源进行访问
        redisUtil.deleteObject(RedisKeyConstants.USER_PERMS_CACHE_PREFIX + SecurityUtil.getUserId());
    }

    /**
     * 刷新 Token
     *
     * @param token        已经过期的Token
     * @param refreshToken 未过期用于刷新的Token
     * @return
     */
    @Override
    public LoginResult refreshToken(String token, String refreshToken) {
        // 获取 refreshToken 中的 token
        String username = jwtUtil.getRefreshTokenUsername(token, refreshToken);
        // 有 username 的话，进行一次登录操作
        if (StringUtils.hasText(username)) {
            UserAuthInfo userAuthInfo = sysUserService.getUserAuthInfo(username);
            return jwtUtil.getLoginResultInfo(new SysUserDetails(userAuthInfo));
        }
        return null;
    }

    /**
     * @param verifyCode    请求中的验证码
     * @param verifyCodeKey 缓存中的验证码
     * @return 返回校验错误码
     */
    @Override
    public ResultCode checkCaptcha(String verifyCode, String verifyCodeKey) {
        // 从 redis获取验证码
        Object cacheVerifyCode = redisUtil.getCacheObject(RedisKeyConstants.VERIFY_CODE_CACHE_PREFIX + verifyCodeKey);
        // redis中获取不到验证码 表示验证码过期
        if (ObjectUtils.isEmpty(cacheVerifyCode)) {
            return ResultCode.VERIFY_CODE_TIMEOUT;
        } else {
            // 验证码进行比对
            if (StrUtil.equals(verifyCode, Convert.toStr(cacheVerifyCode))) {
                return null;
            } else {
                return ResultCode.VERIFY_CODE_ERROR;
            }
        }
    }

    /**
     * 获取验证码
     *
     * @return 返回验证码
     */
    @Override
    public CaptchaResult getCaptcha() {
        // 获取验证码对象
        GifCaptcha captcha = CaptchaUtil.createGifCaptcha(SystemConstants.CAPTCHA_WIDTH, SystemConstants.CAPTCHA_HEIGHT, SystemConstants.CAPTCHA_NUM); // 宽、高、位数
        // 获取验证码
        String captchaCode = captcha.getCode();
        // 验证码图片Base64
        String captchaBase64 = captcha.getImageBase64Data();

        // 生成UUID作为访问Redis验证码时候的Key
        String verifyCodeKey = IdUtil.fastSimpleUUID();
        // 验证码文本缓存至Redis，用于登录校验
        redisUtil.setCacheObject(RedisKeyConstants.VERIFY_CODE_CACHE_PREFIX + verifyCodeKey, captchaCode, 60, TimeUnit.SECONDS);
        return CaptchaResult.builder()
                .verifyCodeKey(verifyCodeKey)
                .verifyCodeBase64(captchaBase64)
                .build();
    }
}
